package resolver

import edu.ucdavis.genomics.metabolomics.binbase.bci.cache.Cache
import edu.ucdavis.genomics.metabolomics.binbase.bci.cache.impl.SimpleCacheFactory
import org.apache.log4j.Logger
import resolver.analyzer.Analyzer
import resolver.interceptor.ResolveableInterceptor
import types.Hit

/**
 *
 * basic class to make it cleaner to implememnt resolvers
 * User: wohlgemuth
 * Date: Feb 8, 2010
 * Time: 11:22:05 AM
 *
 */
abstract class AbstractResolver implements Resolveable, BatchedResolver {

  protected Logger logger = Logger.getLogger("resolver")

  double confidenceLevel

  //do we enable batch execution by default if the batch sets are empty
  boolean batchEnabledByDefault = false

  //which analyzer to use
  Analyzer analyzer = null

  //interceptors
  private Collection<ResolveableInterceptor> interceptors = new HashSet<ResolveableInterceptor>()

  private Set<String> batch = new HashSet<String>()

  /**
   * to improve the query time
   */

  Cache cache = SimpleCacheFactory.getInstance().createCache()

  /**
   * contains a list of registered second level caches
   */
  Set<Cache> associatedCaches = new HashSet<Cache>()

  /**
   * constructor
   */
  public AbstractResolver() {
    this.addCache cache

  }

  def void activateResolver() {

  }

  def void disactivateResolver() {

  }

  /**
   * adds a cache to the associate caches
   */
  void addCache(Cache cache) {
    logger.debug "registering a cache: ${cache}"
    this.associatedCaches.add(cache)
  }
  /**
   * checks if this is already cached
   */
  boolean isCached(String value) {

    //check all registered caches for the value
    for (Cache cache: associatedCaches) {
      if (cache.contains(value.toLowerCase())) {
        return true
      }
    }
    return false
  }

  /**
   * returns the cached object
   */
  Hit getCached(String value) {
    return cache.get(value.toLowerCase())
  }

  /**
   * cache an object
   */
  void cache(Hit hit, String key) {
    if (hit != null && key != null) {
      cache.put(key.toLowerCase(), hit)
    }
  }

  /**
   *   adds a new interceptor
   * */
  public Resolveable addInterceptor(ResolveableInterceptor interceptor) {
    getInterceptors().add(interceptor)
    return this
  }

  /**
   * remove an interceptor
   */
  public Resolveable removeInterveptor(ResolveableInterceptor interceptor) {
    getInterceptors().remove(interceptor)
    return this
  }
  /**
   * returns all interceptors
   */
  public Collection<ResolveableInterceptor> getInterceptors() {
    return interceptors
  }

  /**
   * does the actual interception
   */
  protected Set<String> runInterception(Set<String> collection) {

    logger.debug "before interception: ${collection}"

    getInterceptors().each {ResolveableInterceptor intercept ->
      collection = intercept.intercept(collection)
    }

    logger.debug "after interception: ${collection}"

    return collection
  }

  /**
   * runs the resolver and the interception
   * @param input
   * @return
   */
  public final Set<Hit> resolve(String input) {

    Set<String> text = this.getAnalyzer().analyze(input)
    text = runInterception(text)

    Set<Hit> result = doResolve(text)
    return result
  }

  /**
   * executes the batch resolve           
   * @return
   */
  public final Set<Hit> resolve() {

    Set<String> text = new HashSet<String>()

    batch.each { String s ->
      text.addAll(this.getAnalyzer().analyze(s))
    }

    try {
      text = runInterception(text)


      return doBatchResolve(text)
    }
    finally {
      batch.clear()
    }

  }

  /**
   * adds a batch statement
   * @param value
   */
  public void addBatch(String value) {
    this.batch.add value
  }

  /**
   * set of strings containing the terms to search
   * does the actual resolving
   * @param set
   * @return
   */
  protected Set<Hit> doResolve(Set<String> set) {
    return doBatchResolve(set);
  }

  /**
   * set of strings containing the terms to search
   * executes the batch resolve
   * @param set
   * @return
   */
  protected abstract Set<Hit> doBatchResolve(Set<String> set)
}
